﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using Emil.GMP;
using System.Security.Cryptography;
using NUnit.Framework;

namespace BYU_ECC
{
	/// <summary>
	/// Key generation algorithms utilizing ECDH, or Elliptic Curve Diffie-Hellman
	/// </summary>
    class Decoder
    {
        #region Decoder Members and Properties
		private const int CHUNK_SIZE = 256;

		private static String decodedMessage;
		public static String DecodedMessage {
			get {
				CheckGenerated();
				return decodedMessage;
			}
		}

		private static Point[] decodedMessages;
		public static Point[] DecodedMessages {
			get {
				CheckGenerated();
				return decodedMessages;
			}
		}

        #endregion

        #region Singleton Instance Functions
		private static Decoder instance;
		public Decoder Instance() {
            CheckGenerated();
            return instance;
        }
		public static void GenerateDecoder() {
			instance = new Decoder();
        }
		private Decoder() {
			decodedMessage = "";
			decodedMessages = new Point[Encoder.EncodedMessages.Length];
			Decode();
		}
		private void Decode() {
			EncodedMessage[] messages = Encoder.EncodedMessages;
			for (int i = 0; i < messages.Length; i++) {
				decodedMessages[i] = messages[i].EncodedPoint - KeyPairs.PrivateKeyB * messages[i].ChosenPoint;
				decodedMessage += decodedMessages[i].GetString();
			}
		}
		#endregion

		private static void CheckGenerated()
        {
            if (instance == null)
				throw new DecoderNotGeneratedException();
        }
    }

	class DecoderNotGeneratedException : Exception { }


	[TestFixture]
	class DecoderTest {
        private string[] testStrings = {
                             "hello",
                             BigInt.Two.Power(264).ToString(2),
                             BigInt.Two.Power(530).ToString(2),
                             BigInt.Two.Power(1500).ToString(2) 
                        };

		[Test]
        public void TestDecoderPoints() {
            ParameterGenerator.GenerateTestParameters(KeySizeEnum.Size192);
            KeyPairs.GenerateKeyPairs();
            Point testPoint = new Point(ParameterGenerator.GenerateRandomBigInt(BigInt.Two.Power(32)),
                                        ParameterGenerator.GenerateRandomBigInt(BigInt.Two.Power(32)));
            Encoder.GenerateEncoder(testPoint);
			Decoder.GenerateDecoder();
			Assert.IsTrue(Decoder.DecodedMessages.Length==1);
			Assert.IsTrue(Decoder.DecodedMessages[0]==testPoint);
		}

        [TestCase(KeySizeEnum.Size192)]
        [TestCase(KeySizeEnum.Size256)]
        [TestCase(KeySizeEnum.Size384)]
        [TestCase(KeySizeEnum.Size521)]
		public void TestDecoderStrings(KeySizeEnum keySize) {
            ParameterGenerator.GenerateTestParameters(keySize);
            KeyPairs.GenerateKeyPairs();
			Encoder.GenerateEncoder(testStrings[0]);
			Decoder.GenerateDecoder();
			Assert.IsTrue(Decoder.DecodedMessage == Encoder.OriginalMessage);

			Encoder.GenerateEncoder(testStrings[1]);
			Decoder.GenerateDecoder();
			Assert.IsTrue(Decoder.DecodedMessage == Encoder.OriginalMessage);

            Encoder.GenerateEncoder(testStrings[2]);
            Decoder.GenerateDecoder();
            Assert.IsTrue(Decoder.DecodedMessage == Encoder.OriginalMessage);

            Encoder.GenerateEncoder(testStrings[3]);
            Decoder.GenerateDecoder();
            Assert.IsTrue(Decoder.DecodedMessage == Encoder.OriginalMessage);
		}

	}
}

